package cn.caplike.demo.repository.design.pattern.combined.annotation.definition;

import cn.caplike.demo.repository.design.pattern.combined.annotation.ApiCache;
import com.alibaba.fastjson.parser.deserializer.PropertyProcessable;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.Objects;

/**
 * 反序列化抽象描述符<br>
 * <p>
 * 如果实现类的 field 标注了 {@link ApiDataAdapter},
 * 提供根据当前缓存的 {@link FinanceType} 和 {@link FinanceVersion} 自动转为 {@link ApiDataAdapter.Finance} 指定 filedName 的对象的特性
 * </p>
 *
 * @author LiKe
 * @date 2019-11-12 09:50
 */
public abstract class DeserializeDescriptor implements Serializable, PropertyProcessable {

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
    }

    @Override
    public Type getType(String name) {
        return PropertyProcessableHelper.getTypeHelper(name, this.getClass());
    }

    @Override
    public void apply(String name, Object value) {
        Field field = PropertyProcessableHelper.applyHelper(name, this.getClass());
        if (Objects.nonNull(field)) {
            field.setAccessible(true);
            try {
                field.set(this, value);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Description: {@link PropertyProcessable} 实现方法抽象
     *
     * @author LiKe
     * @date 2019-11-12 09:41:14
     */
    private static class PropertyProcessableHelper {
        /**
         * Description:  根据key和当前财务类型版本信息找出当前属性TYPE
         *
         * @param fieldName   当前属性名
         * @param targetClazz 目标对象的 CLASS 对象
         * @return java.lang.reflect.Type
         * @author LiKe
         * @date 2019/11/10 17:44
         */
        static Type getTypeHelper(String fieldName, Class<?> targetClazz) {
            for (Field field : targetClazz.getDeclaredFields()) {
                ApiDataAdapter annotation = field.getAnnotation(ApiDataAdapter.class);
                if (Objects.nonNull(annotation)) {
                    ApiDataAdapter.Finance[] financeAnnotatedCandidates = annotation.value();
                    for (ApiDataAdapter.Finance finance : financeAnnotatedCandidates) {
                        if (
                                ApiCache.get(ApiCache.Key.FINANCE_TYPE).equals(finance.type().name()) &&
                                        (ApiCache.get(ApiCache.Key.FINANCE_VERSION) + "_" + ApiCache.get(ApiCache.Key.FINANCE_TYPE)).equals(finance.version().name()) &&
                                        fieldName.equals(finance.fieldName())
                        ) {
                            return field.getGenericType();
                        }
                    }

                }
            }
            return null;
        }

        /**
         * Description:  根据key和当前财务类型版本信息找出当前属性Field对象
         *
         * @param fieldName   当前属性名
         * @param targetClazz 目标对象的 CLASS 对象
         * @return java.lang.reflect.Field
         * @author LiKe
         * @date 2019/11/10 17:46
         */
        static Field applyHelper(String fieldName, Class<?> targetClazz) {
            for (Field field : targetClazz.getDeclaredFields()) {
                ApiDataAdapter annotation = field.getAnnotation(ApiDataAdapter.class);
                if (Objects.nonNull(annotation)) {
                    ApiDataAdapter.Finance[] financeAnnotatedCandidates = annotation.value();
                    for (ApiDataAdapter.Finance finance : financeAnnotatedCandidates) {
                        if (
                                ApiCache.get(ApiCache.Key.FINANCE_TYPE).equals(finance.type().name()) &&
                                        (ApiCache.get(ApiCache.Key.FINANCE_VERSION) + "_" + ApiCache.get(ApiCache.Key.FINANCE_TYPE)).equals(finance.version().name()) &&
                                        fieldName.equals(finance.fieldName())
                        ) {
                            return field;
                        }
                    }

                }
            }
            return null;
        }
    }

}
